package 创建型模式

import java.math.BigDecimal

/**
 * 工厂方法：创建对象和使用对象是分离的，客户端总是引用抽象工厂和抽象产品
 * 定义一个用于创建对象的接口，让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
 */

interface NumberFactory {
    fun parse(s: String): Number

    companion object {
        fun getFactory(): NumberFactory {
            return impl
        }

        private val impl = NumberFactoryImpl()
    }
}

class NumberFactoryImpl : NumberFactory {
    override fun parse(s: String): Number {
        return BigDecimal(s)
    }
}


fun main2() {
    val factory = NumberFactory.getFactory()
    println(factory.parse("123.245"))
}


/**
 * 使用静态方法创建产品的方法称为静态工厂方法，是工厂方法的简化使用
 */
class StaticNumberFactory {
    companion object {
        fun parse(s: String): Number {
            return BigDecimal(s)
        }
    }
}


/**
 * 1. 工厂方法可以隐藏创建产品的细节，且不一定每次都会真正创建产品，完全可以返回缓存的产品，从而提升速度并减少内存消耗。
 * 2. 总是引用接口而非实现类，能允许变换子类而不影响调用方，即尽可能面向抽象编程。
 */

interface Animal {
    fun speak()
}


class Dog : Animal {
    override fun speak() {
        println("Dog says woof")
    }
}

class Cat : Animal {
    override fun speak() {
        println("Cat says meow")
    }
}

interface AnimalFactory {
    fun createAnimal(type: String): Animal?

    companion object {
        fun getFactory(): AnimalFactory {
            return impl
        }

        private val impl = AnimalFactoryImpl()
    }
}

class AnimalFactoryImpl : AnimalFactory {
    override fun createAnimal(type: String): Animal? {
        return when {
            "Dog".equals(type, ignoreCase = true) -> Dog()
            "Cat".equals(type, ignoreCase = true) -> Cat()
            else -> null
        }
    }
}


fun main(args: Array<String>) {
    val factory = AnimalFactory.getFactory()
    factory.createAnimal("Dog")?.speak()
    factory.createAnimal("Cat")?.speak()
}